package com.gateway.springboot.starter.gateway.route;

import com.gateway.common.dto.route.FilterData;
import com.gateway.common.dto.route.PredicateData;
import com.gateway.common.dto.route.RouteData;
import com.gateway.common.dto.sync.RouteFilterSyncData;
import com.gateway.common.dto.sync.RoutePredicateSyncData;
import com.gateway.common.dto.sync.RouteSyncData;
import com.gateway.plugin.base.convert.RouteDataConvert;
import com.gateway.router.base.handler.RouteDataHandler;
import com.gateway.router.base.handler.RouteFilterDataHandler;
import com.gateway.router.base.handler.RoutePredicateDataHandler;
import com.gateway.sync.data.api.RouteDataSubscriber;

import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @program: ahcloud-gateway
 * @description:
 * @author: YuKai Fan
 * @create: 2024/5/18 11:54
 **/
public class CommonRouteDataSubscriber implements RouteDataSubscriber {

    private final RouteDataConvert function;
    private final Map<String, RouteDataHandler> handlerMap;
    private final Map<String, RouteFilterDataHandler> filterHandlerMap;
    private final Map<String, RoutePredicateDataHandler> predicateHandlerMap;

    /**
     * Instantiates a new Common plugin data subscriber.
     *
     * @param routeDataHandlerList the plugin data handler list
     */
    public CommonRouteDataSubscriber(
            final RouteDataConvert function,
            final List<RouteDataHandler> routeDataHandlerList,
            final List<RouteFilterDataHandler> routeFilterDataHandlerList,
            final List<RoutePredicateDataHandler> routePredicateDataHandlerList) {
        this.function = function;
        this.handlerMap = routeDataHandlerList.stream().collect(Collectors.toConcurrentMap(RouteDataHandler::rpcType, e -> e));
        this.filterHandlerMap = routeFilterDataHandlerList.stream().collect(Collectors.toConcurrentMap(RouteFilterDataHandler::filterName, e -> e));
        this.predicateHandlerMap = routePredicateDataHandlerList.stream().collect(Collectors.toConcurrentMap(RoutePredicateDataHandler::predicateName, e -> e));
    }

    @Override
    public void onSubscribe(RouteSyncData routeSyncData) {
        RouteData routeData = function.apply(routeSyncData);
        Optional.ofNullable(
                handlerMap.get(routeData.getRpcType())
        ).ifPresent(handler -> handler.handle(routeData));
    }

    @Override
    public void unSubscribe(RouteSyncData routeSyncData) {
        RouteData routeData = function.apply(routeSyncData);
        Optional.ofNullable(
                handlerMap.get(routeData.getRpcType())
        ).ifPresent(handler -> handler.handle(routeData));
    }

    @Override
    public void onSubscribeFilter(RouteFilterSyncData routeFilterSyncData) {
        FilterData filterData = function.apply(routeFilterSyncData);
        Optional.ofNullable(
                filterHandlerMap.get(filterData.getName())
        ).ifPresent(handler -> handler.handle(filterData));
    }

    @Override
    public void unSubscribeFilter(RouteFilterSyncData routeFilterSyncData) {
        FilterData filterData = function.apply(routeFilterSyncData);
        Optional.ofNullable(
                filterHandlerMap.get(filterData.getName())
        ).ifPresent(handler -> handler.remove(filterData));
    }


    @Override
    public void onSubscribePredicate(RoutePredicateSyncData routePredicateSyncData) {
        PredicateData predicateData = function.apply(routePredicateSyncData);
        Optional.ofNullable(
                predicateHandlerMap.get(predicateData.getName())
        ).ifPresent(handler -> handler.handle(predicateData));
    }

    @Override
    public void unSubscribePredicate(RoutePredicateSyncData routePredicateSyncData) {
        PredicateData predicateData = function.apply(routePredicateSyncData);
        Optional.ofNullable(
                predicateHandlerMap.get(predicateData.getName())
        ).ifPresent(handler -> handler.remove(predicateData));
    }

    @Override
    public void refresh() {
        handlerMap.forEach((k, v) -> v.refresh());
    }

    @Override
    public void refreshPredicate() {
        predicateHandlerMap.forEach((k, v) -> v.refresh());
    }

    @Override
    public void refreshFilter() {
        filterHandlerMap.forEach((k, v) -> v.refresh());
    }
}
